Technical Analysis Of Intel¶

Purpose¶

This phase of the project focuses on conducting an in-depth exploratory data analysis (EDA) of the selected stock. The goal is to extract valuable insights and explore key statistics that will lay the foundation for building a robust stock market forecasting system capable of providing actionable recommendations—Buy, Sell, or Hold.

1.0 Load Data and Calculate Key Statistics¶

Potential stocks of interest¶

- INTC  
- AAPL
- INTC
- MLTX
- TSLA
- HON
InĀ [28]:
# Importing Libraries and Data
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import altair as alt
import mplfinance as mpf
import plotly.graph_objects as go


company_df = pd.read_csv('../data/sp500_companies.csv')
stock_df = pd.read_csv('../data/sp500_stocks.csv')
InĀ [29]:
# Create new columns with Moving Averages and Standard Deviations

stock_df['Date'] = pd.to_datetime(stock_df['Date'])

stock_df['MA_10'] = stock_df.groupby('Symbol')['Close'].rolling(window=10).mean().reset_index(level=0, drop=True)
stock_df['MA_20'] = stock_df.groupby('Symbol')['Close'].rolling(window=20).mean().reset_index(level=0, drop=True)
stock_df['MA_50'] = stock_df.groupby('Symbol')['Close'].rolling(window=50).mean().reset_index(level=0, drop=True)
stock_df['MA_200'] = stock_df.groupby('Symbol')['Close'].rolling(window=200).mean().reset_index(level=0, drop=True)
stock_df['std_10'] = stock_df.groupby('Symbol')['Close'].rolling(window=10).std().reset_index(level=0, drop=True)
stock_df['std_20'] = stock_df.groupby('Symbol')['Close'].rolling(window=20).std().reset_index(level=0, drop=True)
stock_df['std_50'] = stock_df.groupby('Symbol')['Close'].rolling(window=50).std().reset_index(level=0, drop=True)
stock_df['std_200'] = stock_df.groupby('Symbol')['Close'].rolling(window=200).std().reset_index(level=0, drop=True)
InĀ [30]:
# Create new columns with Bollinger Bands for each Moving Average

stock_df['upper_band_10'] = stock_df['MA_10'] + (stock_df['std_10'] * 2)
stock_df['lower_band_10'] = stock_df['MA_10'] - (stock_df['std_10'] * 2)

stock_df['upper_band_20'] = stock_df['MA_20'] + (stock_df['std_20'] * 2)
stock_df['lower_band_20'] = stock_df['MA_20'] - (stock_df['std_20'] * 2)

stock_df['upper_band_50'] = stock_df['MA_50'] + (stock_df['std_50'] * 2)
stock_df['lower_band_50'] = stock_df['MA_50'] - (stock_df['std_50'] * 2)


stock_df['upper_band_200'] = stock_df['MA_200'] + (stock_df['std_200'] * 2)
stock_df['lower_band_200'] = stock_df['MA_200'] - (stock_df['std_200'] * 2)
InĀ [31]:
# Create new columns Indicating Golden Cross and Death Cross

stock_df['Golden_Cross_Short'] = np.where((stock_df['MA_10'] > stock_df['MA_20']) & (stock_df['MA_10'].shift(1) <= stock_df['MA_20'].shift(1)), 1, 0)
stock_df['Golden_Cross_Medium'] = np.where((stock_df['MA_20'] > stock_df['MA_50']) & (stock_df['MA_20'].shift(1) <= stock_df['MA_50'].shift(1)), 1, 0)
stock_df['Golden_Cross_Long'] = np.where((stock_df['MA_50'] > stock_df['MA_200']) & (stock_df['MA_50'].shift(1) <= stock_df['MA_200'].shift(1)), 1, 0)

stock_df['Death_Cross_Short'] = np.where((stock_df['MA_10'] < stock_df['MA_20']) & (stock_df['MA_10'].shift(1) >= stock_df['MA_20'].shift(1)), 1, 0)
stock_df['Death_Cross_Medium'] = np.where((stock_df['MA_20'] < stock_df['MA_50']) & (stock_df['MA_20'].shift(1) >= stock_df['MA_50'].shift(1)), 1, 0)
stock_df['Death_Cross_Long'] = np.where((stock_df['MA_50'] < stock_df['MA_200']) & (stock_df['MA_50'].shift(1) >= stock_df['MA_200'].shift(1)), 1, 0)
InĀ [32]:
# Create new columns for MACD, Signal Line and MACD Histogram

def calculate_macd(df, short_window=12, long_window=26, signal_window=9):
    # Calculate the short-term EMA
    df['EMA_short'] = df['Close'].ewm(span=short_window, adjust=False).mean()
    
    # Calculate the long-term EMA
    df['EMA_long'] = df['Close'].ewm(span=long_window, adjust=False).mean()
    
    # Calculate the MACD line
    df['MACD'] = df['EMA_short'] - df['EMA_long']
    
    # Calculate the Signal line
    df['Signal'] = df['MACD'].ewm(span=signal_window, adjust=False).mean()
    
    # Calculate the MACD histogram
    df['MACD_Hist'] = df['MACD'] - df['Signal']
    
    return df

stock_df = calculate_macd(stock_df)
InĀ [33]:
# Create new columns for Average True Range (ATR) and True Range (TR)

stock_df['Previous_Close'] = stock_df['Close'].shift(1)

# True Range, Shows the volatility of the stock
stock_df['TR'] = stock_df.apply(
    lambda row: max(
        row['High'] - row['Low'],  # High - Low
        abs(row['High'] - row['Previous_Close']),  # |High - Previous Close|
        abs(row['Low'] - row['Previous_Close'])  # |Low - Previous Close|
    ), axis=1
)

# Average True Range, Shows the average volatility of the stock
stock_df['ATR'] = stock_df['TR'].rolling(window=10).mean()
InĀ [34]:
# Create new columns for Relative Strength Index (RSI)

def calculate_rsi(df, window=10):
    # Calculate daily price changes
    delta = df['Close'].diff()

    # Separate gains and losses
    gain = delta.where(delta > 0, 0)
    loss = -delta.where(delta < 0, 0)

    # Calculate the average gain and average loss
    avg_gain = gain.rolling(window=window, min_periods=1).mean()
    avg_loss = loss.rolling(window=window, min_periods=1).mean()

    # Calculate the Relative Strength (RS)
    rs = avg_gain / avg_loss

    # Calculate the RSI
    rsi = 100 - (100 / (1 + rs))

    return rsi

# Add RSI column to the DataFrame
stock_df['RSI_10_Day'] = calculate_rsi(stock_df)
InĀ [35]:
# Create new columns for 10 Day Rate of Change (ROC)
stock_df['10_Day_ROC'] = ((stock_df['Close'] - stock_df['Close'].shift(10)) / stock_df['Close'].shift(10)) * 100
InĀ [36]:
# Create new columns for 10,20,50 day resistance and support levels
stock_df['Resistance_10_Day'] = stock_df['Close'].rolling(window=10).max()
stock_df['Support_10_Day'] = stock_df['Close'].rolling(window=10).min()
stock_df['Resistance_20_Day'] = stock_df['Close'].rolling(window=20).max()
stock_df['Support_20_Day'] = stock_df['Close'].rolling(window=20).min()
stock_df['Resistance_50_Day'] = stock_df['Close'].rolling(window=50).max()
stock_df['Support_50_Day'] = stock_df['Close'].rolling(window=50).min()
InĀ [37]:
# Create new columns for 10,20,50 day Volume Indicators
stock_df['Volume_MA_10'] = stock_df['Volume'].rolling(window=10).mean()
stock_df['Volume_MA_20'] = stock_df['Volume'].rolling(window=20).mean()
stock_df['Volume_MA_50'] = stock_df['Volume'].rolling(window=50).mean()
InĀ [38]:
# Create new columns for On Balance Volume (OBV)

def create_OBV(df):
    df['OBV'] = 0
    for i in range(1, len(df)):
        if df['Close'].iloc[i] > df['Close'].iloc[i - 1]:
            df.loc[df.index[i], 'OBV'] = df['OBV'].iloc[i - 1] + df['Volume'].iloc[i]
        elif df['Close'].iloc[i] < df['Close'].iloc[i - 1]:
            df.loc[df.index[i], 'OBV'] = df['OBV'].iloc[i - 1] - df['Volume'].iloc[i]
        else:
            df.loc[df.index[i], 'OBV'] = df['OBV'].iloc[i - 1]
    return df

# stock_df = create_OBV(stock_df)

Preview Data with Additional Columns¶

InĀ [39]:
# Preview Data

stock_df['Z-score'] = (stock_df['Close'] - stock_df['Close'].mean()) / stock_df['Close'].std()
stock_df['Daily Return'] = stock_df.groupby('Symbol')['Close'].pct_change(fill_method=None).reset_index(level=0, drop=True)
company_df.fillna(0, inplace=True)
stock_df.fillna(0, inplace=True)
stock_df
Out[39]:
Date Symbol Adj Close Close High Low Open Volume MA_10 MA_20 ... Support_10_Day Resistance_20_Day Support_20_Day Resistance_50_Day Support_50_Day Volume_MA_10 Volume_MA_20 Volume_MA_50 Z-score Daily Return
0 2010-01-04 A 20.434929 22.389128 22.625179 22.267525 22.453505 3815561.0 0.000000 0.00000 ... 0.000 0.000000 0.000 0.000000 0.000 0.0 0.00 0.00 -0.384398 0.000000
1 2010-01-05 A 20.212959 22.145924 22.331903 22.002861 22.324751 4186031.0 0.000000 0.00000 ... 0.000 0.000000 0.000 0.000000 0.000 0.0 0.00 0.00 -0.385545 -0.010863
2 2010-01-06 A 20.141132 22.067240 22.174536 22.002861 22.067240 3243779.0 0.000000 0.00000 ... 0.000 0.000000 0.000 0.000000 0.000 0.0 0.00 0.00 -0.385915 -0.003553
3 2010-01-07 A 20.115025 22.038628 22.045780 21.816881 22.017166 3095172.0 0.000000 0.00000 ... 0.000 0.000000 0.000 0.000000 0.000 0.0 0.00 0.00 -0.386050 -0.001297
4 2010-01-08 A 20.108498 22.031473 22.067240 21.745352 21.917025 3733918.0 0.000000 0.00000 ... 0.000 0.000000 0.000 0.000000 0.000 0.0 0.00 0.00 -0.386084 -0.000325
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1875709 2024-10-28 LYV 118.430000 118.430000 119.389999 116.904999 117.160004 1786063.0 116.653001 115.03400 ... 0.389 233.399994 0.389 749.119995 0.389 18070329.9 16995342.65 12071518.84 0.068235 0.000000
1875710 2024-10-28 INTC 22.920000 22.920000 23.270000 22.559999 22.684999 38933999.0 22.627160 22.78258 ... 0.389 233.399994 0.389 749.119995 0.389 18490356.5 18852739.45 12847144.68 -0.381896 0.000000
1875711 2024-10-28 DNMR 0.389000 0.389000 0.395600 0.370000 0.403000 1270538.0 0.000000 0.00000 ... 0.389 233.399994 0.389 749.119995 0.389 17647780.5 17179579.70 12845380.04 -0.488083 0.000000
1875712 2024-10-28 SPCE 7.740000 7.740000 7.870000 7.142600 7.210000 2533542.0 0.000000 0.00000 ... 0.389 233.399994 0.389 749.119995 0.389 15497806.0 16821441.90 12892494.20 -0.453439 0.000000
1875713 2024-10-29 INTC 22.705000 22.705000 23.139999 22.410000 22.870001 43573446.0 22.620660 22.78833 ... 0.389 233.399994 0.389 749.119995 0.389 19676544.3 17798449.85 13718152.06 -0.382910 -0.009380

1875714 rows Ɨ 51 columns

Column Descriptions¶

  • Date: The date of the stock data entry.
  • Symbol: The ticker symbol representing the stock.
  • Adj Close: The adjusted closing price of the stock, accounting for corporate actions like dividends and stock splits.
  • Close: The closing price of the stock on the given date.
  • High: The highest price at which the stock traded during the day.
  • Low: The lowest price at which the stock traded during the day.
  • Open: The opening price of the stock on the given date.
  • Volume: The number of shares traded during the day.
  • MA_10: The 10-day moving average of the stock's closing price.
  • MA_20: The 20-day moving average of the stock's closing price.
  • MA_50: The 50-day moving average of the stock's closing price.
  • MA_200: The 200-day moving average of the stock's closing price.
  • std_10: The standard deviation of the stock's closing price over the past 10 days.
  • std_20: The standard deviation of the stock's closing price over the past 20 days.
  • std_50: The standard deviation of the stock's closing price over the past 50 days.
  • std_200: The standard deviation of the stock's closing price over the past 200 days.
  • upper_band_10: The upper Bollinger Band based on the 10-day moving average and standard deviation.
  • lower_band_10: The lower Bollinger Band based on the 10-day moving average and standard deviation.
  • upper_band_20: The upper Bollinger Band based on the 20-day moving average and standard deviation.
  • lower_band_20: The lower Bollinger Band based on the 20-day moving average and standard deviation.
  • upper_band_50: The upper Bollinger Band based on the 50-day moving average and standard deviation.
  • lower_band_50: The lower Bollinger Band based on the 50-day moving average and standard deviation.
  • upper_band_200: The upper Bollinger Band based on the 200-day moving average and standard deviation.
  • lower_band_200: The lower Bollinger Band based on the 200-day moving average and standard deviation.
  • Golden_Cross_Short: Indicator for a short-term golden cross, where the 10-day moving average crosses above the 20-day moving average.
  • Golden_Cross_Medium: Indicator for a medium-term golden cross, where the 20-day moving average crosses above the 50-day moving average.
  • Golden_Cross_Long: Indicator for a long-term golden cross, where the 50-day moving average crosses above the 200-day moving average.
  • Death_Cross_Short: Indicator for a short-term death cross, where the 10-day moving average crosses below the 20-day moving average.
  • Death_Cross_Medium: Indicator for a medium-term death cross, where the 20-day moving average crosses below the 50-day moving average.
  • Death_Cross_Long: Indicator for a long-term death cross, where the 50-day moving average crosses below the 200-day moving average.
  • EMA_short: The short-term Exponential Moving Average (EMA) of the stock's closing price.
  • EMA_long: The long-term Exponential Moving Average (EMA) of the stock's closing price.
  • MACD: The Moving Average Convergence Divergence, calculated as the difference between the short-term EMA and the long-term EMA.
  • Signal: The signal line for the MACD, which is the EMA of the MACD line.
  • MACD_Hist: The MACD histogram, calculated as the difference between the MACD line and the signal line.
  • Previous_Close: The closing price of the stock on the previous trading day.
  • TR: The True Range, a measure of the stock's volatility.
  • ATR: The Average True Range, the moving average of the True Range, indicating the average volatility.
  • RSI_10_Day: The 10-day Relative Strength Index, a momentum oscillator that measures the speed and change of price movements.
  • 10_Day_ROC: The 10-day Rate of Change, showing the percentage change in the stock's closing price over the past 10 days.
  • Z-score: The Z-score of the stock's closing price, indicating how many standard deviations the closing price is from the mean.
  • Daily Return: The daily return of the stock, calculated as the percentage change in the closing price from the previous day.

Visualize Data¶

Line Chart of Closing Price¶

InĀ [40]:
alt.data_transformers.disable_max_rows()
def plot_closing_price(df, company,opacity=1):
    filtered_df = df[df['Symbol'] == company]
    chart = alt.Chart(filtered_df).mark_line(color='black', opacity=opacity).encode(
        alt.X('Date:T', title='Date'),
        alt.Y('Close:Q', title='Closing Price'),
        alt.Tooltip(['Date:T', 'Close:Q', 'Volume:Q','RSI_10_Day']),
    ).properties(
        title=f'{company} Closing Price',
        width=800,
        height=400
    ).interactive(
        bind_y=False
    )
    return chart
plot_closing_price(stock_df, 'INTC')
Out[40]:

There has been a strong upwards trend until around 2020 this is due to Intels strong presence in the tech field manufacturing computer chips. Strong downwards trends then began until 2024, this is due to the first reals competetors on the market outperforming intel.Another down trend starts around Q1 of 2024. Overall INTC is a historically strong stock but due to competition and the pandemic has since become volitile, will need to see them regain competitive edge before long term investments but short term can be money maker.

CandleStick Chart¶

InĀ [41]:
def plot_candlestick(df, company,window:list = None,SR_window=10):
    # Fileter data to specified stock and date range
    filtered_df = df[df['Symbol'] == company]
    filtered_df = filtered_df[filtered_df['Date'] >= window[0]]
    filtered_df = filtered_df[filtered_df['Date'] <= window[1]]
    filtered_df['Date'] = pd.to_datetime(filtered_df['Date'])

    df = filtered_df

    # Create the Candlesick Chart
    candlestick = go.Candlestick(
        x=df['Date'],
        open=df['Open'],
        high=df['High'],
        low=df['Low'],
        close=df['Close'],
        name='Candlestick'
        )
    
    # Create the Volume Bar graph
    volume = go.Bar(
        x=df['Date'],
        y=df['Volume'],
        name='Volume',
        marker_color='blue',
        opacity=0.5,
        yaxis='y2'
    )

    # Create the Support and Resistance Lines
    support = go.Scatter(
        x=df['Date'],
        y=df[f'Support_{SR_window}_Day'],
        mode='lines',
        name=f'Support {SR_window} Day',
        line=dict(color='green', width=1)
    )

    resistance = go.Scatter(
        x=df['Date'],
        y=df[f'Resistance_{SR_window}_Day'],
        mode='lines',
        name=f'Resistance {SR_window} Day',
        line=dict(color='red', width=1)
    )

    # Create the Layout for the Chart (Title, Axis Labels, etc.)
    layout = go.Layout(
        title= f'{company} Candlestick Chart From {window[0]} to {window[1]}',
        xaxis=dict(title='Date'),
        yaxis=dict(title='Price', showgrid=True),
        yaxis2=dict(title='Volume', overlaying='y', side='right', showgrid=False),
        xaxis_rangeslider_visible=False,
        hovermode='x unified', # Compare data points on hover
        plot_bgcolor='white'
    )

    # Layer all the charts together into one figure
    fig = go.Figure(
        data=[candlestick, volume, support, resistance],
        layout=layout
        )
    return fig
plot_candlestick(stock_df, 'INTC', window=['2024-06-01', '2024-10-01'],SR_window=20)

The candlestick comfirms much of what the closing price does but zooming in on the past 3 months we can see recent drop due to missing Q2 earning by .08%. Since then the stock has been pretty stagnat with few flucuations; mass hold possible breakout soon. Recent signs show possible growth specifically with the engulfing candle on September 20th. Stock price rising higher than 20 day resistance, not worrying due to recent price drop, volume indicates significance with this breakout. Support Shift??

InĀ [42]:
def plot_moving_average(df, company, color, MA,term):
    filtered_df = df[df['Symbol'] == company]
    chart = alt.Chart(filtered_df).mark_line(color=color).encode(
        alt.X('Date:T', title='Date'),
        alt.Y(f'{MA}:Q', title='{MA}'),
        alt.Tooltip([MA,'Date', 'Close:Q', 'Volume:Q', 'Death_Cross_Short:O', 'Golden_Cross_Short:O', 'Death_Cross_Long:O', 'Golden_Cross_Long:O'])
    ).properties(
        title=f'{company} Moving Average {term}',
        width=800,
        height=400
    ).interactive(
        bind_y=False
    )

    
    return chart
closing_price = plot_closing_price(stock_df, 'INTC', 0.5)
MA_10 = plot_moving_average(stock_df, 'INTC', 'green', 'MA_10','Short Term')
MA_20 = plot_moving_average(stock_df, 'INTC', 'blue', 'MA_20','Short Term')

MA_50 = plot_moving_average(stock_df, 'INTC', 'red', 'MA_50','Long Term')
MA_200 = plot_moving_average(stock_df, 'INTC', 'purple', 'MA_200','Long Term')
short_term_MA = alt.layer(MA_10, MA_20, closing_price)
medium_term_MA = alt.layer(MA_200, MA_50, closing_price)
MA_charts = alt.vconcat(short_term_MA, medium_term_MA)
MA_charts
Out[42]:

The averages also align with previos charts with Short Term Golden Cross also occuring on September 20th, this is a sign buyers will be stepping in and possible gain in the short term. Long term the averages are down with the 200 day showing signs of rise but the 50 day showing signs of decline, the stock price is however about to move above the 50 day average indicating medium term stock rise. Death Cross on May 2nd yet to uncross, not looking good long term

Bollinger Bands¶

InĀ [43]:
def plot_bollinger_bands(df, company, band):
    # Filter data to specified stock and date range
    df = df[df['Symbol'] == company]
    window=['2023-01-01', '2024-10-01']
    df = df[df['Date'] >= window[0]]
    df = df[df['Date'] <= window[1]]
    fig = go.Figure()

    # Create the Close Price Line Chart
    fig.add_trace(
        go.Scatter(
            x=df['Date'],
            y=df['Close'],
            mode='lines',
            name='Close Price'
        )
    )

    # Create the upper band
    fig.add_trace(
        go.Scatter(
            x=df['Date'],
            y=df[f'upper_band_{band}'],
            mode='lines',
            name='Upper Band',
            line=dict(color='red', width=1)
        )
    )

    # Create the lower band
    fig.add_trace(
        go.Scatter(
            x=df['Date'],
            y=df[f'lower_band_{band}'],
            mode='lines',
            fill='tonexty',
            fillcolor='rgba(128, 128, 128, 0.2)',
            name='Lower Band',
            line=dict(color='red', width=1)
        )
    )

    # Update layout
    fig.update_layout(
        title=f'Bollinger Bands for {band} Day Moving Average',
        xaxis_title='Date',
        yaxis_title='Price',
        legend_title='Legend',
        width=1000,
        height=600
    )

    fig.show()

band_10 = plot_bollinger_bands(stock_df, 'INTC', 10)
band_20 = plot_bollinger_bands(stock_df, 'INTC', 20)
band_50 = plot_bollinger_bands(stock_df, 'INTC', 50)
# band_200 = plot_bollinger_bands(stock_df, 'INTC', 200)

The bollinger bands are all widening which indicates a volitile stock, to be expected with possible breakout pending.

Relative Strength Index¶

InĀ [44]:
def plot_RSI(df, company,start):
    filtered_df = df[df['Symbol'] == company]
    filtered_df = filtered_df[filtered_df['Date'] >= start]
    fig, axs = plt.subplots(2, 1, gridspec_kw={'height_ratios': [3, 1]}, figsize=(10, 6))
    
    axs[0].set_title(f'{company} Closing Price')
    axs[0].plot(filtered_df['Date'],filtered_df['Close'], color='black')
    axs[1].axhline(y=70, color='red', linestyle='--')
    axs[1].axhline(y=30, color='green', linestyle='--')
    axs[1].plot(filtered_df['Date'],filtered_df['RSI_10_Day'], color='orange')
    axs[1].set_title('RSI')
    plt.show()

plot_RSI(stock_df, 'INTC', '2024-06-01')
No description has been provided for this image

The RSI indicates that the stock is currently overbought which is likely due to the recent bullish signal from the candlestick chart, this likely lead to an increace of investors. This is worrying due to the signal often leading to a downtrend as seen in july.

InĀ [59]:
from plotly.subplots import make_subplots

def plot_MACD(df, company, start, stop):
    
    # Filter the DataFrame for the specified company and date range
    df = df[(df['Symbol'] == company)] 
    df = df[df['Date'] >= start]
    df = df[df['Date'] <= stop]
    
    # Create a Plotly figure with two subplots
    fig = make_subplots(
        rows=2, 
        cols=1, 
        shared_xaxes=True, 
        vertical_spacing=0.1, 
        subplot_titles=('Close Price', 'MACD')
        )
    
    # Add Close Price graph
    fig.add_trace(go.Scatter(
        x=df['Date'], y=df['Close'],
        mode='lines',
        name='Close Price'
    ), row=1, col=1)
    
    # Add MACD line graph
    fig.add_trace(go.Scatter(
        x=df['Date'], y=df['MACD'],
        mode='lines',
        name='MACD',
        line=dict(color='red')
    ), row=2, col=1)
    
    # Add Signal line graph
    fig.add_trace(go.Scatter(
        x=df['Date'], y=df['Signal'],
        mode='lines',
        name='Signal',
        line=dict(color='blue')
    ), row=2, col=1)
    
    # Add MACD histogram 
    fig.add_trace(go.Bar(
        x=df['Date'], y=df['MACD_Hist'],
        name='MACD Histogram',
        marker_color=['green' if x > 0 else 'red' for x in df['MACD_Hist']]
    ), row=2, col=1)
    
    # Update layout
    fig.update_layout(
        title=f'MACD for {company}',
        xaxis_title='Date',
        yaxis_title='Price',
        legend_title='Legend',
        width=1000,
        height=600
    )
    
    fig.show()
start = pd.to_datetime('01-01-2024')
stop = pd.to_datetime('09-29-2024')
MACD = plot_MACD(stock_df, 'INTC', start, stop)

The MACD indicates that the best time to buy wouldve been around the middle of September, currently bullish signal.